#coding: utf-8

'''
Created on 06/04/2009

@author: iuri.andreazza
'''
#class Tipo:
#    __ciclos = 0
#    __nome = ""
#    
#    def __init__(self, ciclos, nome):
#        self.__ciclos = ciclos
#        self.__nome = nome
#        
#    def __cabecalho(self):
#        print self.__nome
#        
#    def getNome(self):
#        print(self.__nome)
           
class Somador:
    __ciclos = 1;
#    def __init__(self):
#        self.cabecalho();
        
    def cabecalho(self):
        print "Somador",


class Multiplicador:
    __ciclos = 2;
#    def __init__(self):
#        self.cabecalho();
    def cabecalho(self):
        print "Multiplicador",


class EntradaSaida:
    __ciclos = 2;
#    def __init__(self):
#        self.cabecalho();       
    def cabecalho(self):
        print "Memoria"

        
class VLIW:
    __lista = {}; #Lista dos tipos existentes na execução
    __instr = []; #Lista das Instruções que devem ser executadas
    __total = 4;
    add1 = Somador();
    add2 = Somador();
    mul1 = Multiplicador();
    mem = EntradaSaida();
    __listaEmExecucao =[]
    __listaExecutada=[]
    __primeiralinha=1
    
#    def __init__(self):
#        self.__lista[0] = Tipo(1,"Somador");
#        self.__lista[1] = Tipo(1,"Somador");
#        self.__lista[2] = Tipo(2,"Multiplicador");
#        self.__lista[3] = Tipo(2,"EntradaSaida");
        
    def loadInstructions(self, instr):
        self.__instr = instr;
        print str(len(self.__instr))+" linhas de instruções carregadas." #Informa quantas linhas foram carregadas.
        print ""
        
    #Procura a primeira instrução a ser executada
    def procuraPeloPrimeiro(self, parametro, parametroAnt):
        if(parametroAnt==-1 and parametro==0):
            return True
        else: return False
        
    #Verifica se a instrucao possui uma dependencia direta    
    def verificaSeEDependente(self, parametro, OptingIn):
        listaRegistro=[]
        if (parametro!=0):
            for registro in OptingIn: #Para cada registro de OptingIn
                for valor in OptingIn[registro]: #para cada valor do registro
                    if (parametro==valor): #se o parametro existir entre os dependentes
                         listaRegistro.append(registro) #retorna o registro Ex:$T1, tem q averiguar.
        return listaRegistro
        
    def verificaSeJaExecutou(self, registrador):
        for item in self.__listaExecutada:
            if (item==registrador):
                return True
        return False
      #Se a funcao anterior retornou a lista de registros preenchida,
      # verifica se a isntrucao ja foi executada, caso verdadeiro, 
      # executa a funcao   
    def procuraDependencia(self, registrador,OptorIn):
        for registroRegistrador in registrador:#para cada registrador encontrado como dependente
            for registroOptorIn in OptorIn: #procura nos registradores
                if (registroRegistrador==registroOptorIn): #se o registrador estiver em execucao
                    for valorDoRegistro in OptorIn[registroOptorIn]: #pega o valor do registro
                        #Tem que Ve se ja foi executado
                        #if(self.verificaSeJaExecutou(valorDoRegistro)):
                        for executando in self.__listaEmExecucao: #para cada um em execucao
                            if (valorDoRegistro==executando): #Se encontrar o valor
                                return True #Encontrou dependencia
#                        else: 
#                            return True
        return False #Nao encontrou

        
    # Limpa os comandos da lista de execucao e move para a de executados
    # apesar do nome das variaveis, é para todas as listas        
    def limpaEmExecucao(self, listaADD):
        for itemADD in listaADD:
            for itemExecucao in self.__listaEmExecucao:            
                if (itemExecucao==listaADD[itemADD]):
                    self.__listaEmExecucao.remove(listaADD[itemADD])
                    self.__listaExecutada.append(listaADD[itemADD])
                    return True
        return False                       
                               
    # OptorIn: lista dos registradores independentes
    # OptingIn: lista dos registradores que dependem de outros
    
    #os registradores foram separados em listas de acordo com os seus tipos
    #utiliza uma lista de executados e em execucao para controlar as dependencias
    #executa até a ultima instrucao terminar completamente      
    def execute(self, listaADD, listaMUL, listaMEM, OptorIn, OptingIn, listaDepReais ):
        
        ponteiroAdd=0
        ponteiroMul=0
        ponteiroMem=0        
        flagMul=0
        flagMem=0
        flagAdd=0
        contador = 0
        ponteiroAnt = -1
                
        primeiro=0
        
        
        while (contador<self.__instr.__len__()):
#           ADD
            print "ADD: ",
            if (not primeiro and not self.procuraPeloPrimeiro(listaADD[ponteiroAdd], ponteiroAnt)):
                print "Nop",
            else:
                if(ponteiroAdd<listaADD.__len__()):
                    primeiro=1
                    retorno = self.verificaSeEDependente(listaADD[ponteiroAdd], OptingIn)              
                    if (retorno.__len__()==0):
                        print listaADD[ponteiroAdd],
                        ponteiroAnt = listaADD[ponteiroAdd]
                        self.__listaEmExecucao.append(listaADD[ponteiroAdd])
                        ponteiroAdd+=1;
                        contador+=1;
                    else:
                        retornoFinal = self.procuraDependencia(retorno, OptorIn)
                        if (not retornoFinal):
                            print listaADD[ponteiroAdd],
                            ponteiroAnt = listaADD[ponteiroAdd]
                            self.__listaEmExecucao.append(listaADD[ponteiroAdd])
                            ponteiroAdd+=1;
                            contador+=1;
                        else:
                            print "Nop",
                else: print "Nop",
#           ADD
            print "ADD: ",
            if (not primeiro and not self.procuraPeloPrimeiro(listaADD[ponteiroAdd], ponteiroAnt)):
                print "Nop",
            else:
                if(ponteiroAdd<listaADD.__len__()):
                    primeiro=1
                    retorno = self.verificaSeEDependente(listaADD[ponteiroAdd], OptingIn)
                    if (retorno.__len__()==0):
                        print listaADD[ponteiroAdd],
                        ponteiroAnt = listaADD[ponteiroAdd]
                        self.__listaEmExecucao.append(listaADD[ponteiroAdd])
                        ponteiroAdd+=1;
                        contador+=1;
                    else:
                        retornoFinal = self.procuraDependencia(retorno, OptorIn)
                        if (not retornoFinal):
                            print listaADD[ponteiroAdd],
                            ponteiroAnt = listaADD[ponteiroAdd]
                            self.__listaEmExecucao.append(listaADD[ponteiroAdd])
                            ponteiroAdd+=1;
                            contador+=1;
                        else:
                            print "Nop",
                else: print "Nop",
#           MUL
            print "MUL: ",
            if (not primeiro and not self.procuraPeloPrimeiro(listaMUL[ponteiroMul],ponteiroAnt)):
                print "Nop",
            else:
                if (not flagMul and ponteiroMul<listaMUL.__len__()):
                    primeiro=1
                    retorno = self.verificaSeEDependente(listaMUL[ponteiroMul], OptingIn)
                    if (retorno.__len__()==0):
                        print listaMUL[ponteiroMul],
                        self.__listaEmExecucao.append(listaMUL[ponteiroMul])
                        ponteiroMul+=1;
                        flagMul=1
                    else:
                        retornoFinal = self.procuraDependencia(retorno, OptorIn)
                        if (not retornoFinal):
                            print listaMUL[ponteiroMul],
                            self.__listaEmExecucao.append(listaMUL[ponteiroMul])
                            ponteiroMul+=1;
                            flagMul=1
                        else:
                            print "Nop",
                else:
                    print "Nop",
                    flagMul=0
                    if (self.limpaEmExecucao(listaMUL)):
                        contador+=1;                    
#           E/S
            print "E/S: ",
            if (not primeiro and not self.procuraPeloPrimeiro(listaMEM[ponteiroMem],ponteiroAnt)):
                print "Nop",
            else:
                if (not flagMem and ponteiroMem<listaMEM.__len__()):
                    primeiro=1
                    retorno = self.verificaSeEDependente(listaMEM[ponteiroMem], OptingIn)
                    if (retorno.__len__()==0):
                        print listaMEM[ponteiroMem]
                        self.__listaEmExecucao.append(listaMEM[ponteiroMem])
                        ponteiroMem+=1;
                        flagMem=1
                    else:                    
                        retornoFinal = self.procuraDependencia(retorno, OptorIn)
                        if (not retornoFinal):
                            print listaMEM[ponteiroMem]
                            self.__listaEmExecucao.append(listaMEM[ponteiroMem])
                            ponteiroMem+=1;
                            flagMem=1
                        else:
                            print "Nop"
                else:
                    print "Nop"
                    flagMem=0
                    if (self.limpaEmExecucao(listaMEM)):
                        contador+=1;                    
            self.limpaEmExecucao(listaADD)


#-----------------------------------------------------------------------------------------------------
class Operador:
    
    '''
        @var __opName: Nome do Operador (ADD, ADDU, MUL ...)
    '''
    __opName = "";
    
    '''
        @var __operandos: Operandos do Operador
    '''
    __operandos = [];
    
    '''
        @var __comentario: Comentário da linha
    '''
    __comentario = "";
    
    '''
        Construtor padrão
        @author: iuri.andreazza
    '''
    def __init__(self):
        self.__opName = "";
        self.__operandos = [];
        self.__comentario = "";
        
    '''
        Construtor que possibiltia a definição do nome do operador;
        
        @param opName: Nome do Operador (ADD, ADDU, MUL ...)
        @author: iuri.andreazza
    '''
    def __init__(self, opName):
        self.__opName = opName;
        self.__operandos = [];
        self.__comentario = "";
    
    '''
        Construtor que possibilita a definição de todos os dados do operador
        
        @param opName: Nome do Operador (ADD, ADDU, MUL ...)
        @param operandos: Operandos do Operador
        @param comentario: Comentário da linha
    '''
    def __init__(self, opName, operandos, comentario):
        self.__opName = opName;
        self.__operandos = operandos;
        self.__comentario = comentario;    

    '''
        Getters and Setters
    '''

    def getOp(self):
        return self.__opName;
    
    def getOperandos(self):
        return self.__operandos;
    
    def getComentario(self):
        return self.__comentario;

'''
    Class que abstrai o Operador ADD
    
    @author: iuri.andreazza
'''
class ADD(Operador):
    '''
        Construtor do ADD.
        Esse construtor funciona para todos os ADDs (ADD,ADDU,ADDF);
        
        @author: iuri.andreazza
    '''
    def __init__(self, operandos, comentario, type = "ADD"):
        Operador.__init__(self, type, operandos, comentario);
        

class OR(Operador):
    '''
        Construtor do OR.
        Esse construtor funciona para todos os ORs (OR,XOR,NOR);
        
        @author: iuri.andreazza
    '''
    def __init__(self, operandos, comentario, type = "OR"):
        Operador.__init__(self, type, operandos, comentario);


class AND(Operador):
    '''
        Construtor do AND.
        Esse construtor funciona para todos os AND;
        
        @author: iuri.andreazza
    '''
    def __init__(self, operandos, comentario):
        Operador.__init__(self, "AND", operandos, comentario);

class NOT(Operador):
    '''
        Construtor do NOT.
        Esse construtor funciona para todos os NOT;
        
        @author: iuri.andreazza
    '''
    def __init__(self, operandos, comentario):
        Operador.__init__(self, "NOT", operandos, comentario);


class MUL(Operador):
    '''
        Construtor do MUL.
        Esse construtor funciona para todos os MULs (MUL,MULO,MULOU);
        
        @author: iuri.andreazza
    '''
    def __init__(self, operandos, comentario, type = "MUL"):
        Operador.__init__(self, type, operandos, comentario);

class SUB(Operador):
    '''
        Construtor do SUB.
        Esse construtor funciona para todos os SUBs (SUB,SUBU);
        
        @author: iuri.andreazza
    '''
    def __init__(self, operandos, comentario, type = "SUB"):
        Operador.__init__(self, type, operandos, comentario);


class LW(Operador):
    '''
        Construtor do LW.
        
        @author: iuri.andreazza
    '''
    def __init__(self, operandos, comentario):
        Operador.__init__(self, "LW", operandos, comentario);

class SW(Operador):
    '''
        Construtor do LW.
        
        @author: iuri.andreazza
    '''
    def __init__(self, operandos, comentario):
        Operador.__init__(self, "LW", operandos, comentario);
        
#--------------------------------------------------------------------------------------------------------------
class Instruction:
    
    __label = "";
    __instrct = None;
    __instrctType = "fn";
    __pipeStage = -1; #0-"BI", 1-"LR", 2-"OU", 3-"AD", 4-"ER"
    __execCicle = 1;
    
    
    
    def __init__(self, label, instrc, tp = "fn"):
        self.__label = label;
        self.__instrct = instrc;
        self.__pipeStage = -1;
        self.__execCicle = 1;
        self.__instrctType = tp;
        
    def advPipeStage(self):
        self.__pipeStage = self.__pipeStage+1;
    
    def getLabel(self):
        sl = "";
        if (self.__label < 10):
            sl = "0"+str(self.__label);
        else:
            sl = str(self.__label);
        return "I"+sl;
    
    def getCicle(self):
        return self.__execCicle;
    
    def getStage(self):
        return self.__pipeStage;
    
    def advCicle(self):
        self.__execCicle = self.__execCicle + 1;
        
    def resetCicle(self):
        self.__execCicle = 1;
    
    def getType(self):
        return self.__instrctType;
    
    def getInstruct(self):
       return self.__instrct;

    def getInstruction(self):
       s = self.getLabel() + " " + self.getInstruct().getOp()  + " "
       s = s + "$T" + self.getOperandos()[0].getNumero().__str__() + " "
       s = s + "$T" + self.getOperandos()[1].getNumero().__str__() + " "
       s = s + "$T" + self.getOperandos()[2].getNumero().__str__() + " "
       return s
    
    def getOperandos(self):
        return self.__instrct.getOperandos();
    
    def isInBI(self):
        return self.getStage() == 0;
    
    def isInLR(self):
        return self.getStage() == 1;
    
    def isInOU(self):
        return self.getStage() == 2;
    
    def isInAD(self):
        return self.getStage() == 3;
    
    def isInER(self):
        return self.getStage() == 4;

    
#--------------------------------------------------------------------------------------------------------------

'''
    Classe que irá ser o responsavel por ler o fonte ASM
    e interpretar ele.
    
    @author: iuri.andreazza
'''
class AsmParser:
   __fl = None;                            #arquivo ASM
   __parsedInstr = {};                     #Lista de instruções lidas e validadas
   __typeAdd = ["ADDU","ADD", "ADDF"];     #Lista de ADDs possiveis
   __typeMul = ["MUL", "MULO", "MULOU"];   #Lista de MULs possiveis
   __typeSub = ["SUB", "SUBU"];            #Lista de SUBs possiveis
   __typeOr = ["OR", "XOR", "NOR"];        #Lista de ORs possiveis
   __type_R = ["AND", "NOT"];              #Lista de AND ou NOT
   __realDep = {}                          #Lista de dependências reais
   __outputDep = {}                        #Lista de dependências de saída
   __antiDep = {}                          #Lista de antidependềncias
   __typeSomador = {}                      #Lista dos registradores tipo ADD
   __typeMultiplicador = {}                 #Lista dos registradores tipo MUL
   __typeEntradaSaida = {}                  #Lista dos registradores tipo E/S
   regOptorIn = {}                       #Lista de operadores
   regOptingIn = {}                      #Lista de operandos
  
   def getInstr(self):
       return self.__parsedInstr
   def getDepReais(self):
       return self.__realDep;   
   def getSomadores(self):
       return self.__typeSomador
   def getMultiplicadores(self):
       return self.__typeMultiplicador
   def getEntradaSaida(self):
       return self.__typeEntradaSaida
   def getRegOptorIn(self):
       return self.regOptorIn
   def getRegOptingIn(self):
       return self.regOptingIn
   
   def __init__(self):
       self.__parsedInstr = {};
       self.__fl = None;

   def openASMFile(self, fileName):
       self.__fl = open(fileName);

   '''
       Procura antidependência e dependências reais e de saída
   '''
   def __checkDependencies(self, OptorIn = {}, regOptingIn = {}):

       #dependência de saída é quando os registradores são escritos em mais de
       #  uma instrução
       for key in OptorIn.keys():
           if OptorIn[key].__len__() > 1:
               self.__outputDep[key] = OptorIn[key]
#        print "output", self.__outputDep

       #dependência real são os registradores de mesma chave e commesmos valores
       #  de dentro do array, onde um operando é escrito pouco antes de ser       #  manipulado
       #antidependência são os registradores de mesma chave e com osmesmos valores
       #  onde um registrador vai ser reescrito enquanto está sendo manipulado
       #  por uma instrução anterior
       for regOr in OptorIn:
           for regIng in regOptingIn:
               if regOr == regIng:
                   for linO in OptorIn[regOr]:
                       for linI in regOptingIn[regIng]:
                           if linO < linI:
                               #se for nova instrução, cria um novo array
                               if not self.__realDep.has_key(regOr):
#                                   print regOr
                                   self.__realDep[regOr] = []
                               #evita inserir chaves duplicadas
                               if not self.__realDep[regOr].__contains__(linO):
                                   self.__realDep[regOr].append(linO)
                               if not self.__realDep[regOr].__contains__(linI):
                                   self.__realDep[regOr].append(linI)
                           else:
                               if not self.__antiDep.has_key(regOr):
                                   self.__antiDep[regOr] = []
                               if not self.__antiDep[regOr].__contains__(linO):
                                   self.__antiDep[regOr].append(linO)
                               if not self.__antiDep[regOr].__contains__(linI):
                                   self.__antiDep[regOr].append(linI)
       self.__showRealDeps();
#       self.__showAntiDeps();
#       self.__showOutDeps();

   def __showRealDeps(self):
        print "Dependências Reais:";
        for item in self.__realDep:
            print "     " + "{" + item + "}:",;
            print self.__realDep[item];
        print "";
    
   def __showAntiDeps(self):
       print "Anti-Dependências: ";
       for item in self.__antiDep:
           print "     " + "{" + item + "}:",;
           print self.__antiDep[item];
       print ""
   
   def __showOutDeps(self):
       print "Dependências de saída: ";
       for item in self.__outputDep:
           print "     " + "{" + item + "}:",;
           print self.__outputDep[item];
       print ""
        
   def __tryParse(self):
       ln = 0;
       #para cada linha do arquivo ASM
       for lin in self.__fl:
           label = ln; #define o label da instrução
           #prepara a linha para processamento
           lin = lin.upper();  #Normalizando os caracteres
           lin = lin.strip();  #removendo os espaços em branco desnessesários
           lin = lin.split();  #quebrando a linha para ser lida

           comentario = "";
           op = lin.pop(0); #operador   
           
#           print op
           lastIt = lin.pop(); #ultimo dado (pode ser um comentário)

           if(lastIt.strip().startswith(";")):
               comentario = lastIt;
           else:
               lin.append(lastIt); #volta ele para a lista

           #Cria dicionários com as linhas onde é usado cada registrador,
           #  com um dicionário para operandos e outro para operadores
           for i in range(3):
               if lin[i][lin[i].__len__() - 1] == ',':
                   lin[i] = lin[i][:lin[i].__len__() - 1];
               if i == 0:
                   if not self.regOptorIn.has_key(lin[i]):
                       self.regOptorIn[lin[i]] = [];
                   self.regOptorIn[lin[i]].append(label);
               else:
                   if not self.regOptingIn.has_key(lin[i]):
                       self.regOptingIn[lin[i]] = [];
                   self.regOptingIn[lin[i]].append(label);

           params = self.__parseParams(lin);
           if op == "LW":
               self.__parsedInstr[label] = Instruction(label, LW(params, comentario), 'lw');
               self.__typeEntradaSaida[self.__typeEntradaSaida.__len__()]=label;
#               print self.__typeEntradaSaida.__len__();
           elif op == "SW":
               self.__parsedInstr[label] = Instruction(label, SW(params, comentario), 'sw');
               self.__typeEntradaSaida[self.__typeEntradaSaida.__len__()]=label;
#               print self.__typeEntradaSaida.__len__();
           elif op in self.__typeAdd:
               for i in range(len(params)):
                   if(i == 0): params[i].setWriting();
                   else: params[i].setReading();
               self.__parsedInstr[label] = Instruction(label, ADD(params, comentario, op));
               self.__typeSomador[self.__typeSomador.__len__()]=label;
#               print self.__typeSomador.__len__();
           elif op in self.__typeMul:
               for i in range(len(params)):
                   if(i == 0): params[i].setWriting();
                   else: params[i].setReading();
               self.__parsedInstr[label] = Instruction(label, MUL(params, comentario, op));
               self.__typeMultiplicador[self.__typeMultiplicador.__len__()]=label;
#               print self.__typeMultiplicador.__len__();
           elif op in self.__typeSub:
               for i in range(len(params)):
                   if(i == 0): params[i].setWriting();
                   else: params[i].setReading();
               self.__parsedInstr[label] = Instruction(label, SUB(params, comentario, op));
           elif op in self.__typeOr:
               for i in range(len(params)):
                   if(i == 0): params[i].setWriting();
                   else: params[i].setReading();
               self.__parsedInstr[label] = Instruction(label, OR(params, comentario, op));
           elif op in self.__type_R:
               for i in range(len(params)):
                   if(i == 0): params[i].setWriting();
                   else: params[i].setReading();
               if op == self.__type_R[0]:
                   self.__parsedInstr[label] = Instruction(label, AND(params, comentario));
               elif op == self.__type_R[1]:
                   self.__parsedInstr[label] = Instruction(label, NOT(params, comentario));
           else:
               raise AsmPanic("UserError: This code is WRONG! Fix it and then come back");

           ln = ln + 1;
       print self.regOptorIn
       print self.regOptingIn
       self.__checkDependencies(self.regOptorIn, self.regOptingIn);
       return 1;

   def __parseParams(self, params):
       paramLst = [];
       for param in params:
               regNum = 0;
               param  = param.strip();
               if(param[0] == "$"):
                   try:
                       #limpa o nome do Registrador para ver seu numero
                       regParsed = param.replace("$", "");
                       regParsed = regParsed.replace("T", "");
                       regParsed = regParsed.replace("t", "");
                       regParsed = regParsed.replace(",", "");
                       regNum = int(regParsed);
                       paramLst.append(Register(param[1], regNum));
                   except ValueError:
                       raise AsmPanic("Linha: "+self.__instr[self.__pp].getLabel()+" - Valor Incorreto para o Resgistrador");
       return paramLst;

   '''
       Faz o parse do arquivo ASM

       @raise AsmPanic: Ocorreu algum erro inesperado que o parser não conseguiu evitar.
   '''
   def doParse(self):
       if(self.__tryParse() <= 0):
           raise AsmPanic("AHHHHH, ocorreu um erro inesperado duranteo parser!!")
       else:
           return self.__parsedInstr;
#--------------------------------------------------------------------------------------------------------------
class Register():
    
    __type = "T";
    
    __numero = -1;
    
    __value = -1;
    
    __isReading = False;
    
    __isWriting = False;
    
    __isInitialized = False;
    
    def __init__(self, type, num, value = -1):
        self.__type = type;
        self.__numero = num;
        if(value >= 0):
            self.__value = value;
            self.__isInitialized = True;
        else:
            self.__value = -1;
            self.__isInitialized = False;
        
    def isReading(self):
        return self.__isReading;
    
    def isWriting(self):
        return self.__isWriting;
    
    def isInitialized(self):
        return self.__isInitialized;
    
    def setReading(self):
        self.__isReading = True;
        self.__isWriting = False;
        
    def setWriting(self):
        self.__isWriting = True;
        self.__isReading = True;
    
    def getNumero(self):
        return self.__numero;
    
    def getType(self):
        return self.__type;
    
    def getValue(self):
        if(self.isReading()):
            return self.__value;
    
    def setValue(self, val):
        if(self.isWriting()):
            self.__value = val;
        else:
            raise AsmPanic("Registrador tentando ser escrito sem estar habilitado para escrita");
#--------------------------------------------------------------------------------------------------------------

'''
    
'''
class AsmPanic(Exception):
    
    def __init__(self, value):
        self.value = "ASM_Panic: "+value;
        
    def __str__(self):
        return repr(self.value);
#--------------------------------------------------------------------------------------------------------------

'''
    Motor de execução do ASM
    @todo: então manter um... hã, registro dos registradores sendo escritos em runtime.
    @todo: ser capaz de reordenar o codigo
    @author: iuri.andreazza
'''
class AsmEngine:
    
    '''
        @var __instr: Lista das Instruções que devem ser executadas
    '''
    __instr = [];
    
    '''
        @var __pastInstr: Instruções executadas
    '''
    __pastInstr = [];
    
    '''
        @var __tCicles: Dicionário dos Ciclos de cada Instrução
    '''
    __tCicles = {"lw"  : {"BI": 2, "LR": 1, "OU": 2, "AD": 2, "ER":1}, # lw
                 "sw"  : {"BI": 2, "LR": 1, "OU": 2, "AD": 2, "ER":0}, # sw
                 "fn"  : {"BI": 2, "LR": 1, "OU": 2, "AD": 0, "ER":1}, # add, sub, and, or, slt
                 "beq" : {"BI": 2, "LR": 1, "OU": 2, "AD": 0, "ER":0}  # beq
                 };
    
    '''
        @var __pMatriz: Matriz que simula a execução dos Pipelines
    '''
    __pMatriz = []; #matriz que simula a execução dos Pipelines
    
    '''
        @var __pLines: Numero de Linhas na atual execução do Pipeline
    '''
    __pLines = 0; #numero de Pipelines.
    
    '''
        @var __pStages: Estagios da execução do Pipeline
    '''
    __pStages = ["BI","LR","OU","AD","ER"];
    
    '''
        @var __pp: Program Pointer (Indica em que indice do array de instruções está.)
    '''
    __pp = 0; #Program Pointer (Indica em que indice do array de instruções está.
    
    '''
        @var __memory: Array da Memória
    '''
    __memory = [];
    
    '''
        @var __regs: Array dos Registradores
    '''
    __regs = [];
    
    '''
        @var __regsInUse: Array dos Registradores em Uso
    '''
    __regsInUse = [];
    
    __regsNumMax = 32;
    
    '''
       Construtor 
    '''
    def __init__(self, numLines = 5, numRegs = 32, tamMemory = 256):
        self.__instr = [];
        self.__regsNumMax = numRegs;
        for j in range(numRegs):
            self.__regs.append(0);
            
        for j in range(tamMemory):
            self.__memory.append(0);
            
        for i in range(numLines):
            self.__pMatriz.append(None);
    
        
    '''
        Carrega as instruções no Engine e reseta o PP
        
        @param instr: Instruções
        @return: void
    '''
    def loadInstructions(self, instr):
        self.__pp = 0;
        self.__instr = instr;
        print str(len(self.__instr))+" linhas de instruções carregadas." #Informa quantas linhas foram carregadas.
        print ""
    '''
        Executa as instruções
    '''
    def doExecute(self):
        contLine = 1
        
        while(len(self.__instr) > 0):
            if(contLine < 10): 
                strContLine = "0"+str(contLine)
            else:
                 strContLine = str(contLine)
            print strContLine+"-",
            self.__loadInstrcIntoPipe();
            self.advPipes();  
            contLine+=1          
        while(self.__pLines > 0):
            if(contLine < 10): 
                strContLine = "0"+str(contLine)
            else:
                 strContLine = str(contLine)
            print strContLine+"-",
            self.advPipes();
            contLine+=1       
        return 1;
            
    '''
        Indicador se o Pipe está cheio.
        
        @return: boolean: True (cheio)
    '''
    def pipeIsFull(self):
        return len(self.__pMatriz) == self.__pLines;
    
    '''
        Indicador se o Pipe está vazio.
        
        @return: boolean: True (vazio)
    '''
    def pipeIsEmpty(self):
        return len(self.__pMatriz) == 0;
    
    
    '''
        Indicador se o Pipe está carregando uma instrução.
        
        @return: boolean: True (Carregando)
    '''
    def __pipeIsLoadingInstrc(self):
        for it in self.__pMatriz:
            if(it != None):
                if(it.getStage() == 0):
                    return True;
        return False;
    
    '''
        Adiciona uma Instrução ao Pipe
        
        @param instrc: Instrução a Ser adicionada
        @return: void
    '''
    def __addPipeInstruction(self, instrc):
        fSlot = 0;
        for it in self.__pMatriz:
            if(self.__pMatriz[fSlot] == None):
                break;
            else:
                fSlot += 1;
                
        self.__pMatriz[fSlot] = instrc;
        self.__pMatriz[fSlot].advPipeStage();
        self.__pLines += 1;
    
    
    '''
        Carrega uma instrução ao Pipe em caso de ele não estar cheio 
        ou não estar carregando uma instrução.
        
        @raise AsmPanic: Erro Generalizado durante a execução
        @return: void
    '''
    def __loadInstrcIntoPipe(self):
        if(self.pipeIsFull() == False and not self.__pipeIsLoadingInstrc()): # Se o Pipe não está cheio e não está carregando alguma instrc.
            self.__addPipeInstruction(self.__instr[self.__pp]); #adiciona a instrução ao Pipe
            regs = self.__instr[self.__pp].getOperandos(); #retorna os Operandos da Instrução
            
            #reconhecer os registradores 
            self.__addRegs(regs);
            self.__pastInstr.append(self.__instr.pop(self.__pp)); #remove a instrução da lista de execução
            self.__pp += 1;
    
    '''
        Adiciona os registradores utilizados na instrução
    '''
    def __addRegs(self, regs):
        for reg in regs:
            if(reg.getNumero() > self.__regsNumMax): #caso o numero do registrador tenha sido colocado alem do maximo de regs q tem o sistema
                raise AsmPanic("Linha: "+self.__instr[self.__pp].getLabel()+" - Registrador Inexistente");
            self.__regsInUse.append(reg.getNumero()); #adiciona o Indice do registrador na lista dos que estao sendo usados
    
    def __rmRegs(self, regs):
        for reg in regs:
            self.__regsInUse.remove(reg.getNumero());
    
    '''
        Reporta o avanço dos estagios do Pipe
        
        @param instrc: Instrução
        @param msg: Mensagem
        @return: void
    '''
    def __reportAdvPipe(self, instrc, msg = " "):
        if(instrc != None):
            print "["+str(instrc.getLabel()) + " - " +str(instrc.getStage())+"]"+msg,;
        else:
            print msg,;
    '''
        Retorna a próxima Instrução a ser executada a partir da instrução indicada
        
        @param it: Instrução
        @return: Instruction: Próxima instrução
    '''
    def __getNextInstrcPipe(self, it):
        idx = self.__pMatriz.index(it); #acha o indice da instrução informada no pipe
        if(idx < self.__pLines-1): # se o indice da instrução no Pipe não é a Ultima Linha 
            if(self.__pMatriz[idx+1] != None): #testa se o seguinte tem uma instrução carregada
                return self.__pMatriz[idx+1]; #retorna a proxima instrução no pipe
            else:
                return it; #retorna o proprio item
        else:            
            return it; #retorna o proprio item
        
    
    '''
        @todo: FAZER nessa função o tratamento de conflitos para os registradores e tal.
    '''
    def advPipes(self):
        stageInUse = []; #array dos estagios em uso
        i = 0;
#        "BI","LR","OU","AD","ER"
        for it in self.__pMatriz:
            if(it != None): #se a linha do pipe não está vazia
                if(it.getStage() < len(self.__pStages) ): #Se N passou por todos os estagios
                    if(it.getStage() not in stageInUse): #Se o estagio da Instrução Atual NÃO ESTA EM USO por outra instrução
                        nextIt = self.__getNextInstrcPipe(it); # pega a próxima instrução no Pipe
                        if(nextIt.getStage() == 0 and it.getStage() == 1 and nextIt.getCicle() == 1): #se o seguinte tá carregando e o atual está nos registradores não deve avançar de estagio
                            self.__reportAdvPipe(None, "[  NOOP ] ");
                        else:
                            stageInUse.append(it.getStage()); #Adiciona o estagio para os estagios em uso
                            numCiclos = self.__tCicles[it.getType()][self.__pStages[it.getStage()]]; #busca a quantidade de ciclos para a instrução
                            if(numCiclos == 0):
                                if (it.getStage()!=4):
                                    it.advPipeStage();
                                strAvan = "*";  
                            else:
                                strAvan = " ";
                            if(it.getStage() < len(self.__pStages)):
                                self.__reportAdvPipe(it, strAvan);
                                if(it.getCicle() >= numCiclos): #se a instrução nao passo o total de ciclos dela (para aquele estagio da instrução)
                                    it.advPipeStage(); #avança o estagio da instrução
                                    it.resetCicle(); #reseta os ciclos da instrução
                                else: #se nao passo todos os ciclos do estagio avança o ciclo, indicando que deu mais um passo.
                                    it.advCicle(); #avança o ciclo
                            else:
                                self.__reportAdvPipe(None,"[  NOOP ] ");
                                self.__rmRegs(self.__pMatriz[i].getOperandos());
                                self.__pMatriz[i] = None;
                                self.__pLines -= 1;
                    else:
                        self.__reportAdvPipe(None,"[  NOOP ] ");
                else:
                    self.__reportAdvPipe(None,"[  NOOP ] ");
                    self.__rmRegs(self.__pMatriz[i].getOperandos());
                    self.__pMatriz[i] = None;
                    self.__pLines -= 1;
            else: 
                self.__reportAdvPipe(None,"[       ] ");
            i += 1; 
        print "";
#--------------------------------------------------------------------------------------------------------------

def main():
   p = AsmParser();
   p.openASMFile("fonte2.txt");
   v = VLIW();
   v.loadInstructions(p.doParse());
   v.execute(p.getSomadores(),p.getMultiplicadores(),p.getEntradaSaida(), p.getRegOptorIn(),p.getRegOptingIn(),p.getDepReais()) 
   
main()